﻿using System;
using System.Collections.Generic;
using System.Xml;
using Jayden.Dll.Core.Persistence;
using Jayden.Dll.Core.Persistence.Enums;
using Jayden.Dll.Core.Persistence.Models;
using Jayden.Dll.Core.Persistence.Xml;

namespace Jayden.Dll.Core.Membership
{
	public class XmlUserDataAccess : XmlDataAccess<User>, UserDataAccess
	{
		public XmlUserDataAccess(Configuration config, UnitOfWork uow, Entity entity) : base(config, uow, entity) { }

		private string m_XPathUserName = null;
		protected string XPathUserName(string username)
		{
			if (m_XPathUserName == null)
				m_XPathUserName = XmlHelper.XPath(Entity, Entity["UserName"]);
			return string.Format(m_XPathUserName, username);
		}

		private string m_XPathEmail = null;
		protected string XPathEmail(string email)
		{
			if (m_XPathEmail == null)
				m_XPathEmail = XmlHelper.XPath(Entity, Entity["Email"]);
			return string.Format(m_XPathEmail, email);
		}

		public User ReadByName(string username)
		{
			string xpath = XPathUserName(username);
			using (XmlNodeProxy root = GetRoot(false))
			{
				XmlNode node = root.Node.SelectSingleNode(xpath);
				if (node == null)
					return null;
				return CreateFromXmlElement(node as XmlElement);
			}
		}

		public User ReadByEmail(string email)
		{
			string xpath = XPathEmail(email);
			using (XmlNodeProxy root = GetRoot(false))
			{
				XmlNode node = root.Node.SelectSingleNode(xpath);
				if (node == null)
					return null;
				return CreateFromXmlElement(node as XmlElement);
			}
		}

		public List<User> FindAll(int page, int pageSize, out int totalRecords)
		{
			List<User> users = new List<User>();
			using (XmlNodeProxy root = GetRoot(false))
			{
				foreach(XmlNode node in root.Node.ChildNodes)
					if(node is XmlElement && node.Name == Entity.Table.TableName)
						users.Add(CreateFromXmlElement(node as XmlElement));
			}
			totalRecords = users.Count;
			return users;
		}

		public List<User> FindByName(string nameLike, int page, int pageSize, out int totalRecords)
		{
			List<User> users = new List<User>();
			using (XmlNodeProxy root = GetRoot(false))
			{
				foreach (XmlNode node in root.Node.ChildNodes)
					if (node is XmlElement && node.Name == Entity.Table.TableName)
					{
						XmlAttribute attribute = node.Attributes["UserName"];
						if(attribute != null && attribute.Value.Contains(nameLike))
							users.Add(CreateFromXmlElement(node as XmlElement));
					}
			}
			totalRecords = users.Count;
			return users;
		}

		public List<User> FindByEmail(string emailLike, int page, int pageSize, out int totalRecords)
		{
			List<User> users = new List<User>();
			using (XmlNodeProxy root = GetRoot(false))
			{
				foreach (XmlNode node in root.Node.ChildNodes)
					if (node is XmlElement && node.Name == Entity.Table.TableName)
					{
						XmlAttribute attribute = node.Attributes["Email"];
						if (attribute != null && attribute.Value.Contains(emailLike))
							users.Add(CreateFromXmlElement(node as XmlElement));
					}
			}
			totalRecords = users.Count;
			return users;
		}


		protected override User CreateFromXmlElement(XmlElement elt)
		{
			User obj = null;
			if (elt != null && elt.Name == Entity.Table.TableName)
			{
				ObjectId oid = UnitOfWork.NewObjectId(Entity);
				AssignObjectIdXmlElement(oid, elt);
				obj = UnitOfWork.GetRegistered<User>(oid);
				if (obj != null)
					return obj;
				// extract data for creating the membership user object
				string name = GetPropertyValueFromElement(Entity["UserName"], elt) as string;
				long memberId = Convert.ToInt64(GetPropertyValueFromElement(Entity["MemberId"], elt));
				string email = GetPropertyValueFromElement(Entity["Email"], elt) as string;
				string passwordQuestion = GetPropertyValueFromElement(Entity["PasswordQuestion"], elt) as string;
				string comment = GetPropertyValueFromElement(Entity["Comment"], elt) as string;
				bool isApproved = Convert.ToBoolean(GetPropertyValueFromElement(Entity["IsApproved"], elt));
				bool isLockedOut = Convert.ToBoolean(GetPropertyValueFromElement(Entity["IsLockedOut"], elt));
				DateTime creationDate = (DateTime)GetPropertyValueFromElement(Entity["CreationDate"], elt);
				DateTime lastLoginDate = (DateTime)GetPropertyValueFromElement(Entity["LastLoginDate"], elt);
				DateTime lastActivityDate = (DateTime)GetPropertyValueFromElement(Entity["LastActivityDate"], elt);
				DateTime lastPasswordChangedDate = (DateTime)GetPropertyValueFromElement(Entity["LastPasswordChangedDate"], elt);
				DateTime lastLockoutDate = (DateTime)GetPropertyValueFromElement(Entity["LastLockoutDate"], elt);
				obj = new User(UnitOfWork, "Jayden", name, memberId, email, passwordQuestion, comment, isApproved, isLockedOut, creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, lastLockoutDate);
				foreach (Property p in Entity.Properties)
					p.SetValue(obj, GetPropertyValueFromElement(p, elt));
				obj.State = ObjectState.Clean;
			}
			return obj;
		}


		public List<User> Search(string term, bool name, bool email, bool firstName, bool lastName, int page, int pageSize, out int totalRecords)
		{
			throw new NotImplementedException();
		}
	}
}
